﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
using XCode.Entity;
using System.Collections;
using System.Web;
using XCMSData;

namespace PageTemplateLib
{
    /// <summary>
    /// ［语法］
    /// 嵌套：      <%template 模板名%>
    /// 单值变量：  {v:变量名}
    /// 数据集：    {变量名[行号][列名]}
    ///             只能是继承于Entity的数据集
    /// 判断：      <%if 变量 要判断的值%>...<%else%>...<%/if%>
    /// 循环：      <%loop 循环索引变量 循环次数%>...</loop>
    /// </summary>
    public class PageTemplate
    {
        private static Regex[] r = new Regex[20];
        private Dictionary<string, IList<Entity>> dic1 = new Dictionary<string, IList<Entity>>();
        private Dictionary<string, string> dic2 = new Dictionary<string, string>();
        private static string _SkinPath;
        /// <summary>
        /// 皮肤路径
        /// </summary>
        public static string SkinPath
        {
            get { return _SkinPath; }
            set { _SkinPath = value; }
        }

        public PageTemplate()
        {
            RegexOptions options;
            if (Environment.Version.Major == 1)
            {
                options = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline;
            }
            else
            {
                options = RegexOptions.IgnoreCase | RegexOptions.Singleline;
            }

            //嵌套
            r[0] = new Regex(@"<%template (?<tplname>[^\[\]\{\}\s]+)%>", options);

            //循环
            r[1] = new Regex(@"<%loop \{i:(?<rowindex>[^\[\]\{\}\s]+)\} (?<count>[0-9]+)%>(?<loopbody>[^\[\]\s]+?)<%\/loop%>", options);

            //子循环
            r[2] = new Regex(@"(?<subloop><%loop \{i:([^\[\]\{\}\s]+)\} (?<count>[0-9]+)%>(?<loopbody>([\w\W]*?))<%\/loop%>)", options);

            //单值变量
            r[5] = new Regex(@"\{v:(?<vname>[^\[\]\{\}\s\/]+)\}", options);

            //对象变量
            r[6] = new Regex(@"(\{(?<table>[^\[\]\{\}\s]+)\[(?<rowsvaluename>[^\[\]\{\}\s]+)\]\[(?<columnsvaluename>[^\[\]\{\}\s]+)\]\})", options);

            //数字
            r[7] = new Regex(@"(?<value>[0-9]+)", options);

            //判断
            r[3] = new Regex(@"<%if (?<dataname>" + r[6] + @"||" + r[5] + @"||" + r[7] + @") (?<value>(?<v>[0-9]+)||(?<exp>(?<num1>[0-9]+)%(?<num2>[0-9]+)))%>(?<ifbody>[\s\S]+?)<%\/if%>", options);
            r[4] = new Regex(@"<%if (?<dataname>" + r[6] + @"||" + r[5] + @"||" + r[7] + @") (?<value>(?<v>[0-9]+)||(?<exp>(?<num1>[0-9]+)%(?<num2>[0-9]+)))%>(?<ifbody>[\s\S]+?)<%else%>(?<elsebody>[\s\S]+?)<%\/if%>", options);

        }

        #region 添加数据
        /// <summary>
        /// 添加数据集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tableName"></param>
        /// <param name="dataSrc">继承自Entity的数据集</param>
        /// <returns></returns>
        public bool AddData<T>(string tableName, IList<T> dataSrc)
        {
            try
            {
                IList<Entity> src = new List<Entity>();
                foreach (T item in dataSrc)
                {
                    Entity o = item as Entity;
                    src.Add(o);
                }

                dic1.Add(tableName, src);
            }
            catch (Exception e)
            {
                Console.Write(e.ToString());
                return false;
            }
            return true;
        }

        /// <summary>
        /// 添加单值变量
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="dataSrc"></param>
        /// <returns></returns>
        public bool AddData(string tableName, string dataSrc)
        {
            try
            {
                dic2.Add(tableName, dataSrc);
            }
            catch (Exception e)
            {
                Console.Write(e.ToString());
                return false;
            }
            return true;
        }
        #endregion

        #region 分析模板

        /// <summary>
        /// 获取模板
        /// </summary>
        /// <param name="skinName">皮肤名</param>
        /// <param name="templateName">模板名</param>
        /// <returns></returns>
        public string GetTemplate(string skinName, string templateName)
        {
            //string tplSrc = LoadTemplateFromFile(skinName, templateName);
            string tplSrc = LoadTemplateFromDatabase(skinName, templateName);

            if (string.IsNullOrEmpty(tplSrc))
            {
                //找不到模板
                return "";
            }
            else
            {
                return ConvertTags(skinName, tplSrc, "", 0);
            }
        }

        private string LoadTemplateFromDatabase(string skinName, string templateName)
        {
            Skin skin = new Skin();
            if (skin.Select(Skin._.SkinName, skinName))
            {
                Template tpl = new Template();
                if (tpl.Select(new string[] { Template._.SkinID, Template._.TemplateName }, new string[] { skin.ID.ToString(), templateName }))
                {
                    return tpl.Content;
                }
            }
            else
            {
                if (skin.Select(Skin._.SkinName, "default"))
                {
                    Template tpl = new Template();
                    if (tpl.Select(new string[] { Template._.SkinID, Template._.TemplateName }, new string[] { skin.ID.ToString(), templateName }))
                    {
                        return tpl.Content;
                    }
                }
            }
            return "";
        }

        private string LoadTemplateFromFile(string skinName, string templateName)
        {
            StringBuilder strReturn = new StringBuilder();

            string pathFormatStr = "{0}{1}{2}{3}{4}.htm";
            string filePath = string.Format(pathFormatStr, Utils.GetMapPath(_SkinPath), System.IO.Path.DirectorySeparatorChar, skinName, System.IO.Path.DirectorySeparatorChar, templateName);

            //如果指定风格的模板文件不存在...
            if (!System.IO.File.Exists(filePath))
            {
                //默认风格的模板是否存在...
                filePath = string.Format(pathFormatStr, Utils.GetMapPath(_SkinPath), System.IO.Path.DirectorySeparatorChar, "default", System.IO.Path.DirectorySeparatorChar, templateName);
                if (!System.IO.File.Exists(filePath))
                {
                    return "";
                }
            }
            using (System.IO.StreamReader objReader = new System.IO.StreamReader(filePath, Encoding.UTF8))
            {
                System.Text.StringBuilder textOutput = new System.Text.StringBuilder();

                textOutput.Append(objReader.ReadToEnd());
                objReader.Close();

                return textOutput.ToString();
            }
        }

        /// <summary>
        /// 转换标签
        /// </summary>
        /// <param name="skinName"></param>
        /// <param name="inputStr"></param>
        /// <param name="rowIndexName"></param>
        /// <param name="rowIndex"></param>
        /// <returns></returns>
        private string ConvertTags(string skinName, string inputStr, string rowIndexName, int rowIndex)
        {
            string strReturn = "";
            string strTemplate;
            strTemplate = inputStr.Replace("\\", "\\\\");
            //strTemplate = strTemplate.Replace("\"", "\\\"");

            ////嵌套 
            strTemplate = GetIncludeString(strTemplate);

            //循环索引 
            strTemplate = strTemplate.Replace("{i:" + rowIndexName + "}", rowIndex.ToString());

            //分析循环
            strTemplate = GetLoopString(strTemplate);

            //判断
            strTemplate = GetIFString(strTemplate);

            //变量
            strTemplate = GetValues(strTemplate);

            strReturn = strTemplate;
            return strReturn;
        }

        #region 分析嵌套 <%template 模板名%>
        /// <summary>
        /// 分析嵌套
        /// </summary>
        /// <param name="strTemplate"></param>
        /// <returns></returns>
        private string GetIncludeString(string strTemplate)
        {
            foreach (Match m in r[0].Matches(strTemplate))
            {
                strTemplate = strTemplate.Replace(m.Groups[0].ToString(), GetTemplate("", m.Groups[1].ToString()));
            }
            return strTemplate;
        }
        #endregion

        #region 分析变量，取值 {v:变量名}
        private string GetValues(string strTemplate)
        {
            //单值变量
            foreach (Match m in r[5].Matches(strTemplate))
            {
                try
                {
                    string vname = dic2[m.Groups["vname"].ToString()];
                    strTemplate = strTemplate.Replace(m.Groups[0].ToString(), vname);
                }
                catch (Exception e)
                {
                    strTemplate = strTemplate.Replace(m.Groups[0].ToString(), m.Groups["vname"].ToString() + "变量不存在");
                }
            }

            //对象变量
            foreach (Match m in r[6].Matches(strTemplate))
            {
                try
                {
                    IList<Entity> e = dic1[m.Groups["table"].ToString()] as IList<Entity>;

                    if (Convert.ToInt32(m.Groups["rowsvaluename"].Value) <= e.Count)
                    {
                        strTemplate = strTemplate.Replace(m.Groups[0].ToString(),
                                        Convert.ToString(e[Convert.ToInt32(m.Groups["rowsvaluename"].Value) - 1][m.Groups["columnsvaluename"].Value]));
                    }
                    else
                    {
                        strTemplate = strTemplate.Replace(m.Groups[0].ToString(), "");
                    }
                }
                catch (Exception err)
                {
                    strTemplate = strTemplate.Replace(m.Groups[0].ToString(), m.Groups["columnsvaluename"].Value + "对象变量不存在");
                }
            }
            return strTemplate;
        }
        /// <summary>
        /// 分析单个变量，取值
        /// </summary>
        /// <param name="dataName"></param>
        /// <returns></returns>
        private string GetValueByDataName(string dataName)
        {
            Match m;
            m = r[6].Match(dataName);
            if (m.Success)
            {
                try
                {
                    IList<Entity> e = dic1[m.Groups["table"].ToString()] as IList<Entity>;
                    return Convert.ToString(e[Convert.ToInt32(m.Groups["rowsvaluename"].Value) - 1][m.Groups["columnsvaluename"].Value]);
                }
                catch (Exception err)
                {
                    return m.Groups["columnsvaluename"].Value + "变量对象不存在";
                }

            }
            m = r[5].Match(dataName);
            int i;
            if (m.Success)
            {
                try
                {
                    string vname = dic2[m.Groups["vname"].ToString()];
                    return vname;
                }
                catch (Exception err)
                {
                    return m.Groups["vname"].ToString() + " 变量不存在";
                }
            }
            else if (int.TryParse(dataName, out i))
            {
                return dataName;
            }
            else
            {
                return "没有添加 " + dataName + " 变量";
            }
        }
        #endregion

        #region 判断嵌套分析函数 <%if 变量 要判断的值%>...<%else%>...<%/if%>
        private string GetIFString(string strTemplate)
        {
            //Regex r1 = new Regex(@"<%if (?<dataname>\{(?<table>[^\[\]\{\}\s]+)\[(?<rowsvaluename>[^\[\]\{\}\s]+)\]\[(?<columnsvaluename>[^\[\]\{\}\s]+)\]\}||\{v:(?<vname>[^\[\]\{\}\s]+)\}) (?<value>[0-9]+)%>");
            Regex r1 = new Regex(@"<%if (?<dataname>" + r[6] + @"||" + r[5] + @"||" + r[7] + @") (?<value>(?<v>[0-9]+)||(?<exp>(?<num1>[0-9]+)%(?<num2>[0-9]+)))%>");
            Regex r2 = new Regex(@"<%/if%>");
            MatchCollection mc1 = r1.Matches(strTemplate);
            //存在有 if 语法则进行分析
            for (int i = 0; i < mc1.Count; i++)
            {
                //先解最里面一层的判断
                MatchCollection mc = r1.Matches(strTemplate);
                int j = 1;
                int ifIndex = mc[mc.Count - j].Index;
                int endIfIndex;
                //查找最后一对正确的 if ... /if 语法
                while (r2.Match(strTemplate, ifIndex).Index == 0 && mc.Count > j)
                {
                    j++;
                    ifIndex = mc[mc.Count - j].Index;
                }
                if (j > mc.Count)
                {
                    return strTemplate;
                }
                endIfIndex = r2.Match(strTemplate, ifIndex).Index;
                //找不到对应的 /if 则表示语法不完整
                if (endIfIndex == 0)
                {
                    return strTemplate;
                }
                //取得判断体
                string subBody = strTemplate.Substring(ifIndex, endIfIndex + @"<%/if%>".Length - ifIndex);
                //分析判断体
                strTemplate = strTemplate.Replace(subBody, GetIFBodyString(subBody));
            }

            return strTemplate;
        }

        /// <summary>
        /// 分析判断体
        /// </summary>
        /// <param name="strTemplate"></param>
        /// <returns></returns>
        private string GetIFBodyString(string strTemplate)
        {
            //分析IF ELSE
            foreach (Match m in r[4].Matches(strTemplate))
            {
                string dataname = m.Groups["dataname"].ToString();
                string value = m.Groups["value"].ToString();

                //求余表达式
                int rs, num1, num2;
                if (value.IndexOf("%") != -1)
                {
                    num1 = Convert.ToInt32(m.Groups["num1"].Value);
                    num2 = Convert.ToInt32(m.Groups["num2"].Value);
                    rs = num1 % num2;
                    value = rs.ToString();
                }

                if (GetValueByDataName(dataname) == value)
                {
                    string ifbody = m.Groups["ifbody"].ToString();

                    StringBuilder body = new StringBuilder();
                    body.Append(ConvertTags("", ifbody, "", 0));
                    strTemplate = strTemplate.Replace(m.Groups[0].ToString(),
                        body.ToString());
                }
                else
                {
                    string elsebody = m.Groups["elsebody"].ToString();

                    StringBuilder body = new StringBuilder();
                    body.Append(ConvertTags("", elsebody, "", 0));
                    strTemplate = strTemplate.Replace(m.Groups[0].ToString(),
                        body.ToString());
                }
            }

            //分析IF
            foreach (Match m in r[3].Matches(strTemplate))
            {
                string dataname = m.Groups["dataname"].ToString();
                string value = m.Groups["value"].ToString();

                //求余表达式
                int rs, num1, num2;
                if (value.IndexOf("%") != -1)
                {
                    num1 = Convert.ToInt32(m.Groups["num1"].Value);
                    num2 = Convert.ToInt32(m.Groups["num2"].Value);
                    rs = num1 % num2;
                    value = rs.ToString();
                }

                if (GetValueByDataName(dataname) == value)
                {
                    string ifbody = m.Groups["ifbody"].ToString();

                    StringBuilder body = new StringBuilder();
                    body.Append(ConvertTags("", ifbody, "", 0));
                    strTemplate = strTemplate.Replace(m.Groups[0].ToString(),
                        body.ToString());
                }
                else
                {
                    strTemplate = strTemplate.Replace(m.Groups[0].ToString(), "");
                }
            }
            return strTemplate;
        }
        #endregion

        #region 循环嵌套处理函数 <%loop 循环索引变量 循环次数%>...</loop>

        //取得循环
        private string GetLoopString(string strTemplate)
        {
            Regex r1 = new Regex(@"<%loop \{i:(?<rowindex>[^\[\]\{\}\s]+)\} (?<count>[0-9]+)%>");
            Regex r2 = new Regex(@"<%/loop%>");
            MatchCollection mc1 = r1.Matches(strTemplate);
            //存在有 loop 语法则进行分析
            for (int i = 0; i < mc1.Count; i++)
            {
                //先解最里面一层的循环
                //查找最后一个 loop
                //int loopIndex = strTemplate.LastIndexOf(@"<%loop");
                MatchCollection mc = r1.Matches(strTemplate);
                if (mc.Count == 0)
                {
                    return strTemplate;
                }
                int j = 1;
                int loopIndex = mc[mc.Count - j].Index;
                int endLoopIndex;
                //查找最后一对正确的 if ... /if 语法
                while (r2.Match(strTemplate, loopIndex).Index == 0 && mc.Count > j)
                {
                    j++;
                    loopIndex = mc[mc.Count - j].Index;
                }
                if (j > mc.Count)
                {
                    return strTemplate;
                }
                endLoopIndex = r2.Match(strTemplate, loopIndex).Index;
                //找不到对应的 /loop 则表示语法不完整
                if (endLoopIndex == 0)
                {
                    return strTemplate;
                }
                //取得循环体
                string subBody = strTemplate.Substring(loopIndex, endLoopIndex + @"<%/loop%>".Length - loopIndex);
                //分析循环体
                strTemplate = strTemplate.Replace(subBody, GetLoopBodyString(subBody));
            }
            return strTemplate;
        }

        /// <summary>
        /// 分析循环体（无子循环）
        /// </summary>
        /// <param name="strTemplate"></param>
        /// <returns></returns>
        private string GetLoopBodyString(string strTemplate)
        {
            //循环
            //r[1] = new Regex(@"<%loop \{i:(?<rowindex>[^\[\]\{\}\s]+)\} (?<count>[0-9]+)%>(?<loopbody>[^\[\]\s]+?)<%\/loop%>", options);
            r[1] = new Regex(@"<%loop \{i:(?<rowindex>[^\[\]\{\}\s]+)\} (?<count>[0-9]+)%>(?<loopbody>[\w\W]*?)<%\/loop%>");

            foreach (Match m in r[1].Matches(strTemplate))
            {
                int count = int.Parse(m.Groups["count"].ToString());
                string loopBody = m.Groups["loopbody"].ToString();
                string rowIndexName2 = m.Groups["rowindex"].ToString();

                StringBuilder body = new StringBuilder();
                //循环索引从1开始运算
                for (int j = 1; j <= count; j++)
                {
                    body.Append(ConvertTags("", loopBody, rowIndexName2, j));
                }
                strTemplate = strTemplate.Replace(m.Groups[0].ToString(),
                    body.ToString());
            }
            return strTemplate;
        }
        #endregion
        #endregion
    }
}
